//
//  WebExtractSet.m
//  WebClipper
//
//  Created by Daniel Braun on 24/02/07.
//  Copyright 2007 Daniel Braun http://page-appart.net, http://braun.daniel.free.fr All rights reserved.
//

#import "WCWebExtractSet.h"
#import "StringExtension.h"
#import "WCWebExtractItem.h"
#import "WCWebLoadProtocol.h"
#import "WCUrlAccess.h"
#import "WCExtractUrl.h"
#import "WCExtractHtml.h"

@implementation WCWebExtractSet


		
- (id) init {
	self = [super init];
	if (self != nil) {
		urlaccess=[[WCUrlAccess alloc] init];
		itemsToExtract=[[NSMutableArray arrayWithCapacity:10] retain];
		//name=[[NSString stringWithFormat:@"x%p", self]retain];
	}
	return self;
}
- (void) dealloc {
	[urlaccess release];
	[itemsToExtract release];
	[next release];
	[prev release];
	[name release];
	[pageCache release];
	[actualUrl release];
	[bodyVariables release];
	[super dealloc];
}

- (id) initWithCoder:(NSCoder *) coder
{
	//self=[super initWithCoder:coder];
	self=[super init];
	if ([coder allowsKeyedCoding]) {
		urlaccess=[[coder decodeObjectForKey:@"urlaccess"]retain];
		itemsToExtract=[[coder decodeObjectForKey:@"itemsToExtract"]retain];
		name=[[coder decodeObjectForKey:@"name"]retain];
		if (!name) name=[[NSString stringWithFormat:@"%p", self]retain];
	}
	return self;
}

- (void)encodeWithCoder:(NSCoder *)coder
{
	//[super encodeWithCoder:coder];
	if ( [coder allowsKeyedCoding] ) {
		[coder encodeObject:urlaccess forKey:@"urlaccess"];
		[coder encodeObject:itemsToExtract forKey:@"itemsToExtract"];
		[coder encodeObject:name forKey:@"name"];
	}
}

- (WCUrlAccess *) urlaccess
{
	return urlaccess;
}
- (NSString *) surl
{
	return [urlaccess stringUrl];
}
#if 1
- (void) setSurl:(NSString *)s
{
	[urlaccess setStringUrl:s];
}
#endif
// actual url, as URL
- (NSURL *) actualUrl
{
	return [self actualUrlOrContent:nil];
}

- (NSURL *) actualUrlOrContent:(NSString **)pcontent
{
	if (pcontent) *pcontent=nil;
	if (actualUrl) {
		//NSLog(@"cached actual url : %@\n", actualUrl);
		return actualUrl;
	}
	NSURL *u= [urlaccess url];
	NSString *sc=[u scheme];
	if ([sc isEqualToString:@"webextract"]) {
		//NSString *s=[u resourceSpecifier];
		NSString *p=[u host];
		if ([p isEqualToString:@"prevurl"]) {
			if (!prev) {
				NSLog(@"prevurl, but prev not set\n");
				return nil;
			}
			NSArray *a=[prev itemsToExtract];
			int i, count = [a count];
			for (i = count-1; i>=0; i--) {
				WCWebExtractItem * ei = [a objectAtIndex:i];
				WCExtractAction *ea=[ei extractAction];
				if (![ea respondsToSelector:@selector(URL)]) {
					continue;
				}
				actualUrl=[[(WCExtractUrl *)ea URL] retain];
				return actualUrl;
			}
		} else if ([p isEqualToString:@"prevhtml"]) {
			//NSLog(@"got prevhtml (%p)\n", pcontent);
			if (!prev) {
				NSLog(@"prevhtml, but prev not set\n");
				return nil;
			}
			NSArray *a=[prev itemsToExtract];
			int i, count = [a count];
			for (i = count-1; i>=0; i--) {
				WCWebExtractItem * ei = [a objectAtIndex:i];
				WCExtractAction *ea=[ei extractAction];
				if (![ea isKindOfClass:[WCExtractHtml class]]) {
					continue;
				}
				NSURL *u;
				u=[prev actualUrl];
				if (!pcontent) return u;
				*pcontent=[NSString stringWithFormat:@"<HTML><BODY>%@</BODY></HTML>",[(WCExtractHtml *)ea htmlContent]];
				return u;

			}
				
		}
	}
	//NSLog(@"u=%@\n", u);
	return u;
}
- (void) setActualUrl:(NSURL *)url
{
	if (0 && ![urlaccess url]) {
		[urlaccess setUrl:url];
	}
	[actualUrl release];
	actualUrl=[url retain];
}
- (NSURL *) officialUrl
{
	return [urlaccess url];
}
- (void) setOfficialUrl:(NSURL *)url
{
	[urlaccess setUrl:url];
}

- (NSNumber *) numItems
{
	return [NSNumber numberWithInt:[itemsToExtract count]];
}
- (int) nItems
{
	return [itemsToExtract count];
}

- (NSArray *) itemsToExtract
{
	return itemsToExtract;
}
- (void) setItemsToExtract:(NSArray *)it
{
	[itemsToExtract release];
	itemsToExtract=[it retain];
}

- (void) setHtmlTitle:(NSString *)s
{
	if (!s) return;
	if (![s length]) return;
	if (!name) [self setName:[s lowercaseStringRemovingAccents]];
}
- (NSString *) name
{
	return name ? name : @"unnamed";
}
- (void) setName:(NSString *) n
{
	[name release];
	name=[n retain];
}
- (NSDictionary *) processExtractionWithController:(NSObject <WCWebLoadProtocol>  *)webCtrl
{
	NSAssert(webCtrl, @"need a web loader");
	DOMHTMLElement *root=[webCtrl rootDOM];
	if (!root) return nil;
	[self extractPageVariableFrom:root];
	NSMutableDictionary *res=[NSMutableDictionary dictionaryWithCapacity:10];
	unsigned int i, count = [itemsToExtract count];
	for (i = 0; i < count; i++) {
		WCWebExtractItem * ei = [itemsToExtract objectAtIndex:i];
		NSDictionary *d=[ei processExtractionWithDom:root skipAction:NO fromUrl:actualUrl/*[urlaccess url]*/];
		NSAssert([d count]==1, @"strange");
		[res addEntriesFromDictionary:d];
	}
	
	return res;
}

- (NSString *) jsCodeForParserArgs:(NSArray *)arg
{
	NSString *r=@"";
	unsigned int i, count = [itemsToExtract count];
	for (i = 0; i < count; i++) {
		WCWebExtractItem * ex = [itemsToExtract objectAtIndex:i];
		r=[r stringByAppendingString:[ex jsCode]];
	}
	return r;
}

- (NSString *) jsCode
{
	NSString *z=[[NSString stringFromResourceFile:@"js.1"] 
		parseWithActions:[NSDictionary dictionaryWithObjectsAndKeys:
						@"jsCodeForParserArgs:", @"parsers",
						 nil]
			     for:self andSimpleReplacement:[NSDictionary dictionaryWithObjectsAndKeys:
				     [[self officialUrl]absoluteString], @"url",@"unnamed", @"name",
				     nil]];
	
	return z;
}

- (WCWebExtractSet *) nextExtractSet
{
	return next;
}
- (void) setNextExtractSet:(WCWebExtractSet *)w
{
	[next release];
	next=[w retain];
}
- (WCWebExtractSet *) prevExtractSet
{
	return prev;
}
- (void) setPrevExtractSet:(WCWebExtractSet *)w;
{
	[prev release];
	prev=[w retain];
}

- (void) setPageCache:(id) pc
{
	[self setPageCache:pc dom:nil];
}
- (void) setPageCache:(id) pc dom:(DOMHTMLElement *)dom
{
	[pageCache release];
	pageCache=[pc retain];
	if (dom) [self extractPageVariableFrom:dom];
}
- (id) pageCache
{
	return pageCache;
}

// extract form variables from dom document

static void extractVar(DOMHTMLElement *el, NSMutableDictionary *d)
{
	for (;el; el=(DOMHTMLElement *)[el nextSibling]) {
		if (![el isKindOfClass:[DOMHTMLElement class]]) continue;
		if (![el nodeName])  continue;
		//NSLog(@"extractVar : process %@\n", [el nodeName]);
		if ([[[el nodeName]lowercaseString] isEqualToString:@"input"]) {
			//NSLog(@"got input %@ (%@)\n", el, [el outerHTML]);
			NSString *n,*v;
			n=[el getAttribute:@"name"];
			v=[el getAttribute:@"value"];
			//NSLog(@"n=%@ v=%@\n", n,v);
			if (n && v) {
				[d setObject:v forKey:n];
			}
		} 
		DOMHTMLElement *e=(DOMHTMLElement *)[el firstChild];
		if (e /*&& [e isKindOfClass:[DOMHTMLElement class]]*/)  {
			extractVar(e,d);
		}
	}
	
}


- (void) extractPageVariableFrom:(DOMHTMLElement*)dr
{
	NSMutableDictionary *d=[NSMutableDictionary dictionaryWithCapacity:20];
	extractVar(dr, d);
	//NSLog(@"got %d variables: %@\n", [d count], [d allKeys]);
	[self setBodyVariables:d];
}

- (NSDictionary *) bodyVariables
{
	return bodyVariables;
}
- (void) setBodyVariables:(NSDictionary *)d
{
	if (bodyVariables==d) return;
	[bodyVariables release];
	bodyVariables=[d retain];
}


- (NSArray *) extractVariables
{
	NSMutableArray *ea=[NSMutableArray arrayWithCapacity:10];
	unsigned int i, count = [itemsToExtract count];
	for (i = 0; i < count; i++) {
		WCWebExtractItem * wi = [itemsToExtract objectAtIndex:i];
		NSString *n=[NSString stringWithFormat:@"%@.%@", name, [wi name]];
		[ea addObject:n];
	}
	return ea;
}

- (NSString *) description
{
	return [NSString stringWithFormat:@"WCWebExtractSet page %@", name];
}


@end
